#!/usr/bin/env python3
# -*- coding: utf-8 -*-
' main entry '
__author__ = 'pingwu you'

#切记本地模块文件名不要与系统内置模块名重名，否则有可能导入的是本地模块，造成异常！！
import asyncio
from asyncio.events import set_event_loop
import threading

balance=0
#DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, 
# use "async def" instead
@asyncio.coroutine
def hello(name,second):    
    global balance
    print('Hello world%s! (%s)' %(name,threading.currentThread()))
    # 异步调用asyncio.sleep(1):
    # yield from语法可以让我们方便地调用另一个generator
    # evtloop线程不会等待asyncio.sleep()，而是直接中断并执行下一个消息循环
    # 当asyncio.sleep()返回时，线程就可以从yield from拿到返回值（此处是None），然后接着执行下一行语句。
    r = yield from asyncio.sleep(second)
    '''
    切记虽然协程在单个线程中执行，可以不太考虑共享变量的逻辑问题！！！
    但是切记将原来加锁的代码块，封装在一个执行块中，不要被yield分割！！！否则还是会出现共享问题！！
    '''
    balance +=5
    r = yield from asyncio.sleep(second)
    balance -=5
    print('Hello again%s   balance结果：%s   (%s)' %(name,str(balance),threading.currentThread()))

@asyncio.coroutine
def wget(host):
    print('wget %s...' % host)
    connect = asyncio.open_connection(host, 80)
    reader, writer = yield from connect
    header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' % host
    writer.write(header.encode('utf-8'))
    yield from writer.drain()
    while True:
        line = yield from reader.readline()
        if line == b'\r\n':
            break
        print('%s header > %s' % (host, line.decode('utf-8').rstrip()))
    # Ignore the body, close the socket
    writer.close()

'''
loop.run_xxx() 家族的函数都是阻塞的，比如 run_until_complete() 会等到给定的 coroutine 完成再结束，
而 run_forever() 则会永远阻塞当前线程，直到有人停止了该 event loop 为止。
所以在同一个线程里，两个 event loop 无法同时 run，但这不能阻止您用两个线程分别跑两个 event loop。

默认情况下 get_event_loop() 只会在线程帮您创建新的 event loop，
    并且在线程中多次调用始终返回该 event loop；
可以采用loop=new_event_loop(),然后set_event_loop(loop)。
    new_event_loop()是创建一个event loop对象，而set_event_loop(eventloop对象)是将event loop对象指定为当前线程的event loop，
    一个线程内只允许运行一个event loop，不要一个线程有两个event loop交替运行。
'''
def start_evtloop(secene=1,doclose=False):    
    if(secene==1):
        # 获取EventLoop:
        loop = asyncio.get_event_loop()
        # hello()返回gen生成器 两个coroutine是由同一个线程并发执行的。
        tasks = [hello(" 1111 ",1),hello(" 2222 ",2), hello(" 3333 ",1)]
        #loop.run_until_complete(hello())
        loop.run_until_complete(asyncio.wait(tasks))
        #消息循环一旦关闭就无法再循环了，就像数据库连接一样被释放了
        #而对于get_event_loop只会获取同一个evtloop对象
        if(doclose):
            loop.close()
    else:
        # 获取EventLoop:
        loop = asyncio.get_event_loop()        
        tasks = [wget(host) for host in ['www.sina.com.cn', 'www.sohu.com', 'www.163.com']]
        #loop.run_until_complete(hello())
        loop.run_until_complete(asyncio.wait(tasks))
        #消息循环一旦关闭就无法再循环了，就像数据库连接一样被释放了
        #而对于get_event_loop只会获取同一个evtloop对象
        if(doclose):
            loop.close()

def start_evtloop222(secene=1):    
    if(secene==1):
        # 创建新的EventLoop:
        loop = asyncio.new_event_loop()
        set_event_loop(loop)
        # hello()返回gen生成器 两个coroutine是由同一个线程并发执行的。
        tasks = [hello(" 1111 ",1),hello(" 2222 ",2), hello(" 3333 ",1)]
        #loop.run_until_complete(hello())
        loop.run_until_complete(asyncio.wait(tasks))        
        loop.close()
        print('最终balance结果：%s'%balance)
    else:
        # 创建新的EventLoop:
        loop = asyncio.new_event_loop()
        set_event_loop(loop)
        tasks = [wget(host) for host in ['www.sina.com.cn', 'www.sohu.com', 'www.163.com']]
        #loop.run_until_complete(hello())
        loop.run_until_complete(asyncio.wait(tasks))
        loop.close()

